package Account

import (
	"Identity/common"
	"bytes"
	"fmt"
	"reflect"
	"errors"
	"sync"
)
var (
	ErrTokenAlreadyExist = errors.New("Token already exist in the queue")

	ErrType = errors.New("return value type is not LoveToken_Ptr")
)
const AccountIndexQueueLen = 5

func NewTokenQueue(maxQueuesize uint64) *TokenQueue{
	return &TokenQueue{
		mu:sync.RWMutex{},
		ContainA:make(map[common.Address](*common.Queue)),
		ContainB:make(map[common.Address](*common.Queue)),
		HashOfToken:make(map[common.Hash](*uint64)),
		Queue:common.NewQueue(maxQueuesize,reflect.Ptr),
	}
}

/* 避免双花 */
type TokenQueue struct {
	mu sync.RWMutex
	ContainA map[common.Address](*common.Queue)  //包含A所在queue中的索引
	ContainB map[common.Address](*common.Queue)  //包含B所在queue中的索引
	HashOfToken	map[common.Hash]*uint64
	*common.Queue
}

func (this * TokenQueue)checkQueueLenValidForOut(outLen uint64 ) error{
	if err := this.CheckQueueLenForOut(outLen) ; err != nil {
		return err
	}
	return nil
}

func (this * TokenQueue)checkQueueLenValidForJoin(joinLen uint64 ) error{
	if err := this.CheckQueueLenForJoin(joinLen) ; err != nil{
		return err
	}

	return nil
}

func (this *TokenQueue)JoinToken(token  *LoveToken) error{
	this.mu.RLock()
	defer  this.mu.RUnlock()
	return this.joinToken(token)
}
//从尾加
func (this *TokenQueue)joinToken(token  *LoveToken) error{
	err := this.checkQueueLenValidForJoin(1)
	if err != nil{
		return err
	}

	// 先判断token在队列中是否存在
	if _,ok := this.HashOfToken[token.Hash()] ; ok{
		return ErrTokenAlreadyExist
	}

	if err := this.Join(token) ; err != nil{
		return err
	}

	index := this.Len()-1
	//插入Hash==>TOKEN
	this.HashOfToken[token.Hash()] = &index

	if !bytes.Equal(token.data.AAddress[:] , common.EmptyAddress[:]){
		// 创建队列
		if this.ContainA[token.data.AAddress] == nil  {
			this.ContainA[token.data.AAddress] = common.NewQueue(AccountIndexQueueLen,reflect.Uint64)
		}
		//加入索引
		err := this.ContainA[token.data.AAddress].Join(this.Len()-1) //加入Token在TokenQueue中的index序号
		if err != nil {
			return err
		}
	}

	if !bytes.Equal(token.data.BAddress[:] , common.EmptyAddress[:]){
		// 创建队列
		if this.ContainB[token.data.BAddress] == nil  {
			this.ContainB[token.data.BAddress] = common.NewQueue(AccountIndexQueueLen,reflect.Uint64)
		}
		//加入索引
		err := this.ContainB[token.data.BAddress].Join(this.Len()-1) //加入Token在TokenQueue中的index序号
		if err != nil {
			return err
		}
	}

	return nil
}
func (this * TokenQueue)OutToken() (*LoveToken,error){
	this.mu.Lock()
	defer this.mu.Unlock()

	return this.outToken()
}
//从头出
func (this * TokenQueue)outToken() (*LoveToken,error){

	err := this.checkQueueLenValidForOut(1)
	if err != nil{
		return nil,err
	}

	// 要出队的这个index 在this.queue中的位置
	var index uint64 = 0

	res ,err  := this.Out()
	if err!= nil {
		return nil , err
	}

	token,ok := res.(*LoveToken)
	if !ok {
		return nil , errors.New("TokenQueue::outToken error:outToken type is not LoveToken ")
	}

	//删除 txHash-->Token
	delete(this.HashOfToken,token.Hash())

	if !bytes.Equal(token.data.AAddress[:] , common.EmptyAddress[:]){
		fmt.Println( *this.ContainA[token.data.AAddress])
		//删除ContainA 对应的index value
		if err  := this.ContainA[token.data.AAddress].DeleteValue(index);err!= nil  {
			panic(fmt.Sprintln("not find this value in TokenQueue.ContainA : ",  err))
		}

		// 删除队列
		if this.ContainA[token.data.AAddress].Empty()   {
			delete(this.ContainA,token.data.AAddress)
		}
	}

	if !bytes.Equal(token.data.BAddress[:] , common.EmptyAddress[:]){
		//删除ContainA 对应的index value
		if   err  :=this.ContainB[token.data.BAddress].DeleteValue(index) ;err != nil {
			panic(fmt.Sprintln("not find this value in TokenQueue.ContainA : ",err ))
		}

		// 删除队列
		if this.ContainB[token.data.BAddress].Empty()   {
			delete(this.ContainB,token.data.BAddress)
		}
	}

	return token,err
}

func (this * TokenQueue)OutIndexToken(index uint64) (*LoveToken,error){
	this.mu.Lock()
	defer this.mu.Unlock()
	return this.outIndexToken(index)
}

func (this * TokenQueue)outIndexToken(index uint64 ) (*LoveToken,error){

	res ,err  := this.OutIndex(index)
	if err!= nil {
		return nil , err
	}

	token,ok := res.(*LoveToken)
	if !ok {
		return nil , errors.New("TokenQueue::outToken error:outToken type is not LoveToken ")
	}

	//删除 txHash-->Token
	delete(this.HashOfToken,token.Hash())

	if !bytes.Equal(token.data.AAddress[:] , common.EmptyAddress[:]){
		//删除ContainA 对应的index value
		if ok,err  := this.ContainA[token.data.AAddress].DeleteValueForType(index);!ok  {
			panic(fmt.Sprintln("not find this value in TokenQueue.ContainA : ",  err))
		}

		// 删除队列
		if this.ContainA[token.data.AAddress].Empty()   {
			delete(this.ContainA,token.data.AAddress)
		}
	}

	if !bytes.Equal(token.data.BAddress[:] , common.EmptyAddress[:]){
		//删除ContainA 对应的index value
		if   ok,err  :=this.ContainB[token.data.BAddress].DeleteValueForType(index) ;!ok  {
			panic(fmt.Sprintln("not find this value in TokenQueue.ContainA : ",err ))
		}

		// 删除队列
		if this.ContainB[token.data.BAddress].Empty()   {
			delete(this.ContainB,token.data.BAddress)
		}
	}

	return token,err
}

func (this * TokenQueue)GetIndexByTokenHash(hash common.Hash) (indexPointer *uint64, exist bool) {
	this.mu.RLock()
	defer this.mu.RUnlock()

	return this.getIndexByTokenHash(hash)
}

func (this * TokenQueue)getIndexByTokenHash(hash common.Hash) (indexPointer *uint64, exist bool) {

	indexPointer  , exist = this.HashOfToken[hash]
	if !exist {
		return nil ,false
	}else{
		return indexPointer,true
	}
}



func (this * TokenQueue)GetIndexQueueByTokenAAddress( Aaddr common.Address)*common.Queue {
	this.mu.RLock()
	defer this.mu.RUnlock()

	return this.getIndexQueueByTokenAAddress(Aaddr)
}

func (this * TokenQueue)getIndexQueueByTokenAAddress( Aaddr common.Address)*common.Queue {

	return this.ContainA[Aaddr]
}



func (this * TokenQueue)GetIndexQueueByTokenBAddress(Baddr common.Address) *common.Queue {
	this.mu.RLock()
	defer this.mu.RUnlock()

	return this.getIndexQueueByTokenBAddress(Baddr)
}

func (this * TokenQueue)getIndexQueueByTokenBAddress(Baddr common.Address) *common.Queue {

	return this.ContainB[Baddr]

}


func (this *TokenQueue)OutLoveTokenByIndex(index uint64) (*LoveToken,error) {
	this.mu.Lock()
	defer this.mu.Unlock()

	return this.outLoveTokenByIndex(index)
}

func (this *TokenQueue)outLoveTokenByIndex(index uint64) (*LoveToken,error) {

	t,err := this.OutIndex(index)
	if err != nil{
		return nil ,err
	}
	if token ,ok := t.(*LoveToken);!ok{
		return nil,errors.New("TokenQueue store value_type is not *LoveToken")
	}else{
		return token,nil
	}

}

func(this *TokenQueue)GetTokenByIndex(index uint64 ) (*LoveToken,error){
	this.mu.Lock()
	defer this.mu.Unlock()
	v,err := this.GetByIndex(index)
	if err != nil{
		return nil,err
	}

	if token,ok := v.(*LoveToken);!ok{
		return nil,ErrType
	}else{
		return token,nil
	}

}